/**
 * 
 */
package cz.cuni.mff.abacs.burglar;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import cz.cuni.mff.abacs.burglar.logics.DataMap;
import cz.cuni.mff.abacs.burglar.logics.ExecutingMap;
import cz.cuni.mff.abacs.burglar.logics.planning.instructions.Instruction;
import cz.cuni.mff.abacs.burglar.logics.storage.XMLLoader;
import cz.cuni.mff.abacs.burglar.logics.storage.XMLSaver;
import cz.cuni.mff.abacs.burglar.visual.multithreading.PlanningListener;
import cz.cuni.mff.abacs.burglar.visual.multithreading.PlanningThread;
import cz.cuni.mff.abacs.burglar.visual.multithreading.PlanningThread.Type;


/**
 * 
 * 
 * @author abacs
 *
 */
public class LevelGenerator implements PlanningListener {
	
	
	/** The string printed to the user if the input parameters are invalid */
	protected static String USAGE_STRING = 
		"options: \n" + 
		"\t[-m %s]\tinput xml file\n" +
		"\t[-l %d]\toutput xml file\n" +
		"\t[-t %d]\trequired number of traprooms" +
		"If there is no input file defined, the program uses standard input.\n" +
		"If there is no output file defined, the program uses standard output." +
		"If there is no defined number of required traps, the program" + 
		" looks for it in a map definition, if finds none, it creates no traps.";
	
	
	// -------------------------------------------------------------------------
	
	
	/**  */
	private ExecutingMap _map; 
	
	
	private PlanningThread _planningThread = null;
	
	
	// -------------------------------------------------------------------------
	
	
	protected LevelGenerator() {	}
	
	
	// -------------------------------------------------------------------------
	
	
	protected void load(String mapName) {
		this._map = XMLLoader.load(mapName);
	}
	
	
	protected void load(InputStream inputStream) {
		this._map = XMLLoader.load(inputStream);
	}
	
	
	protected void save(String levelName) {
		XMLSaver.save(_map, levelName);
	}
	
	
	protected void save(OutputStream outputStream) {
		XMLSaver.save(_map, outputStream);
	}
	
	
	protected void startPlanning() {
		// start placing guards on the map:
		this._planningThread = 
				new PlanningThread(
						this._map,
						Type.SELECTING_TRAP_ROOMS,
						this
				);
		
		this._planningThread.start();
	}
	
	
	protected void setRequiredNumberOfTraps(int number) {
		this._map.setRequiredTrapRoomCount(number);
	}
	
	
	// -------------------------------------------------------------------------
	
	
	@Override
	public void planningFinished(
			List<Instruction> resultedInstructions,
			PlanningThread thread
	) {
		// empty, not required
	}


	@Override
	public void planningFinished(
			List<Instruction> resultedInstructions,
			List<Integer> avoidedTrapRooms,
			PlanningThread thread
	) {
		// empty, not required
	}


	@Override
	public void selectingTrapRoomsFinished(
			List<Integer> trapRooms,
			PlanningThread thread
	) {
		DataMap map = (DataMap)this._map;
		
		List<List<Integer>> components = map.breakToComponents(trapRooms);
		
		for(List<Integer> component : components){
			if(component.size() > 1){
				((ExecutingMap)map).addGuardPatrol(component);
			}else{
				map.addCameraToRoom(component.get(0));
			}
		}
		
		// invalidates the planning thread pointer to show that
		// the planning has finished
		this._planningThread = null;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	/** 
	 * the implicit inputs and outputs are standard input/output.
	 * 
	 * arguments:
	 * "-m %s": input map name
	 * "-l %s": output level name
	 * "-t %d" required number of traprooms
	 */
	public static void main(String[] args) {
		
		boolean hasInputFile = false;
		boolean hasOutputFile = false;
		boolean hasRequiredNumber = false;
		
		String inputFile = "";
		String outputFile = "";
		int trapRoomNumber = 0;
		
		for(int index = 0; index < args.length; index++){
			// 
			if(args[index].equals("-m")){
				if(index + 1 < args.length){
					hasInputFile = true;
					inputFile = args[index + 1];
					index++;
				}else{
					System.err.println(USAGE_STRING);
					System.exit(-1);
				}
			}
			// 
			if(args[index].equals("-l")){
				if(index + 1 < args.length){
					hasOutputFile = true;
					outputFile = args[index + 1];
					index++;
				}else{
					System.err.println(USAGE_STRING);
					System.exit(-1);
				}
			}
			// 
			if(args[index].equals("-t")){
				if(index + 1 < args.length){
					try{
						trapRoomNumber = Integer.valueOf(args[index + 1]);
						hasRequiredNumber = true;
					}catch(Exception e){
						System.err.println(USAGE_STRING);
						System.exit(-1);
					}
					index++;
				}else{
					System.err.println(USAGE_STRING);
					System.exit(-1);
				}
			}
			
		}
		
		LevelGenerator generator = new LevelGenerator();
		
		if(hasInputFile){
			generator.load(inputFile);
		}else{
			generator.load(System.in);
		}
		
		if(hasRequiredNumber)
			generator.setRequiredNumberOfTraps(trapRoomNumber);
		
		generator.startPlanning();
		
		while(generator._planningThread != null){
			// TODO more sophisticated waiting
		}
		
		if(hasOutputFile){
			generator.save(outputFile);
		}else{
			generator.save(System.out);
		}
		
		System.exit(0);
	}
	
	
}
